package ink.yuanchu.picachoframework.security;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import ink.yuanchu.picachoframework.message.Message;
import ink.yuanchu.picachoframework.util.JwtTokenUtil;
import lombok.SneakyThrows;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.bind.annotation.RequestBody;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

/**
 * Created with IntelliJ IDEA.
 *
 * @author ziyuan
 * @Date: 2021/02/20/12:39
 * @Description:
 */
public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {

    private AuthenticationManager authenticationManager;


    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
        // 设置登录URL
        super.setFilterProcessesUrl("/picachoframework/user/login");
    }

    /**
     * 验证操作 接收并解析用户凭证
     * @param request
     * @param response
     * @return
     * @throws AuthenticationException
     */
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        // 从输入流中获取到登录的信息
        // 创建一个token并调用authenticationManager.authenticate() 让Spring security进行验证
        String json = getBodyTxt(request);
        Map map = jsonToMap(json);
        String username = map.get("username").toString();
        String password = map.get("password").toString();
        return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username,password));
    }

    private String getBodyTxt(HttpServletRequest request){
        BufferedReader br;
        try {
            br = request.getReader();
            String str, wholeStr = "";
            while((str = br.readLine()) != null){
                wholeStr += str;
            }
            br.close();
            return wholeStr;
        }catch (IOException e) {
            e.printStackTrace();
            logger.error(e.getMessage());
            return null;
        }
    }

    private Map jsonToMap(String json){
        try {
            ObjectMapper objectMapper = new ObjectMapper();
            Map map = objectMapper.readValue(json, Map.class);
            if (map == null){
                System.out.println("map null");
            }
            return map;
        }catch (JsonProcessingException e) {
            e.printStackTrace();
            logger.error(e.getMessage());
            return null;
        }
    }

    /**
     * 验证【成功】后调用的方法
     * 若验证成功 生成token并返回
     * @param request
     * @param response
     * @param chain
     * @param authResult
     * @throws IOException
     */
    @Override
    protected void successfulAuthentication(HttpServletRequest request,HttpServletResponse response,FilterChain chain,Authentication authResult) throws IOException {

        User user= (User) authResult.getPrincipal();

        // 从User中获取权限信息
        Collection<? extends GrantedAuthority> authorities = user.getAuthorities();
        // 创建Token
        String token = JwtTokenUtil.createToken(user.getUsername(), authorities.toString());

        // 设置编码 防止乱码问题
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");

        // 在请求头里返回创建成功的token
        // 设置请求头为带有"Bearer "前缀的token字符串
        String reToken = JwtTokenUtil.TOKEN_PREFIX + token;
        response.setHeader("token", reToken);

        // 处理编码方式 防止中文乱码
        response.setContentType("text/json;charset=utf-8");
        // 将反馈塞到HttpServletResponse中返回给前台
        //response.getWriter().write(JSON.toJSONString("登录成功"));
        response.getWriter().write(tokenData(reToken,user).toString());
    }


    /**
     * 消息封装
     * @param token
     * @param userForBase
     * @return
     */
    private JSONObject tokenData(String token, User userForBase){
        JSONObject jsonObject = new JSONObject();
        JSONObject jsonObject1 = new JSONObject();
        jsonObject1.put("token",token);
        jsonObject.put("token", token);
        jsonObject.put("user", userForBase);
        jsonObject.put("result",jsonObject1);
        jsonObject.put("_headers",jsonObject1);
        return jsonObject;
    }

    /**
     * 验证【失败】调用的方法
     * @param request
     * @param response
     * @param failed
     * @throws IOException
     * @throws ServletException
     */
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        String returnData="";
        JSONObject jsonObject;
        int responseStatus = 200;
        // 账号过期
        if (failed instanceof AccountExpiredException) {
            jsonObject = Message.errorLoginToJson(HttpStatus.UNAUTHORIZED,Message.ACCOUNT_EXPIRED);
            responseStatus = HttpStatus.UNAUTHORIZED.value();
        }
        // 密码错误
        else if (failed instanceof BadCredentialsException) {
            jsonObject = Message.errorLoginToJson(HttpStatus.UNAUTHORIZED,Message.WRONG_PASSWORD);
            responseStatus = HttpStatus.UNAUTHORIZED.value();
        }
        // 密码过期
        else if (failed instanceof CredentialsExpiredException) {
            jsonObject = Message.errorLoginToJson(HttpStatus.UNAUTHORIZED,Message.PASSWORD_EXPIRED);
            responseStatus = HttpStatus.UNAUTHORIZED.value();
        }
        // 账号不可用
        else if (failed instanceof DisabledException) {
            jsonObject = Message.errorLoginToJson(HttpStatus.UNAUTHORIZED,Message.ACCOUNT_NOT_AVAILABLE);
            responseStatus = HttpStatus.UNAUTHORIZED.value();
        }
        //账号锁定
        else if (failed instanceof LockedException) {
            jsonObject = Message.errorLoginToJson(HttpStatus.UNAUTHORIZED,Message.ACCOUNT_LOCKOUT);
            responseStatus = HttpStatus.UNAUTHORIZED.value();
        }
        // 用户不存在
        else if (failed instanceof InternalAuthenticationServiceException) {
            jsonObject = Message.errorLoginToJson(HttpStatus.UNAUTHORIZED,Message.USER_DOES_NOT_EXIST);
            responseStatus = HttpStatus.UNAUTHORIZED.value();
        }
        // 其他错误
        else{
            jsonObject = Message.errorLoginToJson(HttpStatus.UNAUTHORIZED,Message.UNKNOWN_EXCEPTION);
            responseStatus = HttpStatus.UNAUTHORIZED.value();
        }

        // 处理编码方式 防止中文乱码
        response.setContentType("text/json;charset=utf-8");
        response.setStatus(responseStatus);
        // 将反馈塞到HttpServletResponse中返回给前台
        response.getWriter().write(jsonObject.toString());
    }
}
